dnadna.utils.serializers

Implements generic utilities for serialization/deserialization of native Python objects to/from file formats to which they can be serialized.

Functions

filename_or_obj([func, arg, mode])

Decorator for functions which take as one of its arguments either a filename or an already open file-like object.

Classes

DictSerializer()

Base class for serializers/deserializers of JSON-like nested dictionary data structures.

GenericSerializer()

Base class for serializers/deserializers for a specific object type or types.

JSONSerializer()

YAMLSerializer()

class dnadna.utils.serializers.DictSerializer[source]

Bases: GenericSerializer

Base class for serializers/deserializers of JSON-like nested dictionary data structures.

A classmethod match_filename() is used to match a give file (based on its filename) to a given serializer.

language = None

Name of the language / format saved/loaded by this serializer. This is used primarily for introspection purposes, such as applying proper code highlighting to a file.

types = {<class 'collections.abc.Mapping'>, <class 'dict'>}

Types supported by DictSerializer (just dict and collections.abc.Mapping for now).

class dnadna.utils.serializers.GenericSerializer[source]

Bases: object

Base class for serializers/deserializers for a specific object type or types.

A classmethod match_filename() is used to match a given file (based on its filename) to a given serializer. File-like objects are also supported but they must have either a .name or .filename attribute in order to guess the correct implementation to use.

This class should be subclassed for serializers of specific object types. Subclasses should define values for the types and extensions attributes at a minimum.

If one object type supports multiple serialization formats, it is good practice to create a base class which instantiates the types attribute, and then further base classes for each supported format. See for example the DictSerializer base class, and its format-specific subclasses JSONSerializer and YAMLSerializer. While the format-specific serializers may be used directly, a dict object can be loaded or saved using the DictSerializer class directly, since it will automatically guess the correct format to use based on the filename.

binary = False

If True, files are read and written in binary mode by this serializer.

abstract property extensions: List[str]

Built-in mutable sequence.

If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified.

language = None

Name of the language/format saved/loaded by this serializer. This is used primarily for introspection purposes, such as applying proper code highlighting to a file.

Generally not applicable for binary file formats which do not have a useful textual display.

abstract classmethod load(filename, **kwargs)[source]

Read the file given by filename and return its deserialized contents.

Additional keyword arguments are passed to individual subclass loaders depending on the file type, and may not be meaningful unless loading a file in a specific, known serialization format.

Subclasses should override this method to implement the details of deserializing specific file formats.

Note

Subclasses which implement this method should ensure that it is decorated as a classmethod. The method will also be automatically wrapped in the filename_or_obj decorator, which checks whether the filename argument is a filename or file-like object. It is also wrapped in a type-checker which ensures the returned object is one of the types supported by the serializer.

classmethod match_filename(filename)[source]

Given a filename, return True if the file is handled by a given GenericSerializer subclass.

The default implementation matches the filename against the class’s extensions list.

abstract classmethod save(obj, filename, **kwargs)[source]

Serialize the given object to the given filename.

The serialization format is determined automatically by the filename.

Additional keyword arguments are passed to individual subclass’s save methods depending on the file type, and their meaning depends on the target serialization format.

Subclasses should override this method to implement the details of serializing specific file formats.

Note

Subclasses which implement this method should ensure that it is decorated as a classmethod. The method will also be automatically wrapped in the filename_or_obj decorator, which checks whether the filename argument is a filename or file-like object. It is also wrapped in a type-checker which ensures the passed object is one of the types supported by the serializer.

classmethod serializer_for(filename)[source]

Given a filename, return the first GenericSerializer subclass that handles this file, based on the result of its match_filename method.

Examples

Here we use DictSerializer as a concrete example:

>>> from dnadna.utils.config import DictSerializer
>>> DictSerializer.serializer_for('foo.json')
<class 'dnadna.utils.serializers.JSONSerializer'>
>>> DictSerializer.serializer_for('bar.yaml')
<class 'dnadna.utils.serializers.YAMLSerializer'>
>>> DictSerializer.serializer_for('unknown')
Traceback (most recent call last):
...
NotImplementedError: no known serializer for the given filename:
"unknown"
static to_filename(filename_or_obj)[source]

Utility function for use with the filename_or_obj decorator.

If filename_or_obj is already a str or pathlib.Path, return it. Otherwise it checks some heuristics for possible filename attributes on file-like objects. If all else fails it still returns the original file-like object.

abstract property types: Set[type]

Python types that can be serialized by subclasses of this serializer.

class dnadna.utils.serializers.JSONSerializer[source]

Bases: DictSerializer

language = 'json'

Name of the language / format saved/loaded by this serializer. This is used primarily for introspection purposes, such as applying proper code highlighting to a file.

classmethod load(filename_or_obj, **kwargs)[source]

Read the file given by filename and return its deserialized contents.

Additional keyword arguments are passed to individual subclass loaders depending on the file type, and may not be meaningful unless loading a file in a specific, known serialization format.

Subclasses should override this method to implement the details of deserializing specific file formats.

Note

Subclasses which implement this method should ensure that it is decorated as a classmethod. The method will also be automatically wrapped in the filename_or_obj decorator, which checks whether the filename argument is a filename or file-like object. It is also wrapped in a type-checker which ensures the returned object is one of the types supported by the serializer.

classmethod save(obj, filename_or_obj, **kwargs)[source]

Serialize the given object to the given filename.

The serialization format is determined automatically by the filename.

Additional keyword arguments are passed to individual subclass’s save methods depending on the file type, and their meaning depends on the target serialization format.

Subclasses should override this method to implement the details of serializing specific file formats.

Note

Subclasses which implement this method should ensure that it is decorated as a classmethod. The method will also be automatically wrapped in the filename_or_obj decorator, which checks whether the filename argument is a filename or file-like object. It is also wrapped in a type-checker which ensures the passed object is one of the types supported by the serializer.

class dnadna.utils.serializers.YAMLSerializer[source]

Bases: DictSerializer

language = 'yaml'

Name of the language / format saved/loaded by this serializer. This is used primarily for introspection purposes, such as applying proper code highlighting to a file.

classmethod load(filename_or_obj, **kwargs)[source]

Read the file given by filename and return its deserialized contents.

Additional keyword arguments are passed to individual subclass loaders depending on the file type, and may not be meaningful unless loading a file in a specific, known serialization format.

Subclasses should override this method to implement the details of deserializing specific file formats.

Note

Subclasses which implement this method should ensure that it is decorated as a classmethod. The method will also be automatically wrapped in the filename_or_obj decorator, which checks whether the filename argument is a filename or file-like object. It is also wrapped in a type-checker which ensures the returned object is one of the types supported by the serializer.

classmethod save(obj, filename_or_obj, **kwargs)[source]

Serialize the given object to the given filename.

The serialization format is determined automatically by the filename.

Additional keyword arguments are passed to individual subclass’s save methods depending on the file type, and their meaning depends on the target serialization format.

Subclasses should override this method to implement the details of serializing specific file formats.

Note

Subclasses which implement this method should ensure that it is decorated as a classmethod. The method will also be automatically wrapped in the filename_or_obj decorator, which checks whether the filename argument is a filename or file-like object. It is also wrapped in a type-checker which ensures the passed object is one of the types supported by the serializer.

dnadna.utils.serializers.filename_or_obj(func=None, *, arg=0, mode='r')[source]

Decorator for functions which take as one of its arguments either a filename or an already open file-like object.

If given a filename as a string or pathlib.Path, it opens the file (optionally with the given mode) and closes the file when the wrapped function exits.

If given an object of any either type (which is assumed to be duck-typeable as a file object), the object is not closed when the wrapped function exits; this is assumed to be the responsibility of the caller.

By default, the file_or_obj argument is assumed to be the first positional argument of the wrapper function, but the optional arg argument to the decorate can accept either the index of a positional argument, or an argument name. Thus for most method types, arg should be 1 or greater to skip the self argument.